package com.cloud.xtools.common.exception;

import com.cloud.xtools.common.response.ApiResponse;
import com.cloud.xtools.common.response.ResponseBody;
import com.cloud.xtools.common.response.ResponseCode;
import com.cloud.xtools.common.response.ResponseValidatedFailedBody;
import jakarta.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.*;

/**
 * @author Daixinguo
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Map<String, Object>> handleRuntimeException(RuntimeException e) {
        List<String> messageList = Arrays.asList(e.getMessage().replace("\r\n", "").replace("\n;","###").split("###"));

        Map<String, Object> ex = new HashMap<>();
        ex.put("message", messageList);
        if (e.getCause() != null) {
            ex.put("cause", e.getCause().toString());
        }
        ex.put("class", e.getClass());
        ex.put("info", e);

        return ResponseEntity.internalServerError().body(ex);
    }

    // 业务逻辑处理异常
    @ExceptionHandler(ServiceException.class)
    public ApiResponse<String> handleServiceException(ServiceException e) {
        ResponseCode responseCode =ResponseCode.ERROR;
        ResponseBody<String> responseBody = new ResponseBody<>(responseCode.getCode(), e.getMessage());
        return new ApiResponse<>(responseBody, responseCode.getHttpStatus());
    }

    // 表单验证错误异常捕获
    // 期望返回格式
    // {
    //     "code": 0,
    //     "message": "表单参数验证失败",
    //     "errors": {
    //         "password": [
    //             "密码 必须介于 6 - 16 个字符之间。"
    //         ]
    //     }
    // }

    // @Validated 验证抛出的异常捕获
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ResponseValidatedFailedBody<Map<String, ArrayList<String>>>> handleConstraintViolationException(ConstraintViolationException ex) {
        Map<String, ArrayList<String>> errors = new HashMap<>();
        System.out.println(ex.getConstraintViolations().stream().toList());
        ex.getConstraintViolations().forEach(violation -> {
            // System.out.println(Arrays.stream(violation.getExecutableParameters()).toList());

            // 参数的多个验证不通过信息只显示一个
            // errors.put(violation.getPropertyPath().toString(), violation.getMessage());

            String pathField = violation.getPropertyPath().toString();
            String field = pathField.replaceAll(".*\\.(.*)", "$1");
            // System.out.println(field);

            // 参数的所有验证不通过信息都显示
            if(errors.get(field) == null){
                ArrayList<String> errorMsgs = new ArrayList<>();
                errorMsgs.add(violation.getMessage());
                errors.put(field, errorMsgs);
            } else {
                ArrayList<String> errorMsgs = errors.get(field);
                errorMsgs.add(violation.getMessage());
                errors.put(field, errorMsgs);
            }
        });

        ResponseCode responseCode =ResponseCode.VALIDATED;
        ResponseValidatedFailedBody<Map<String, ArrayList<String>>> responseValidatedFailedBody = new ResponseValidatedFailedBody<>(responseCode.getCode(), responseCode.getMessage(), errors);
        return new ResponseEntity<>(responseValidatedFailedBody, responseCode.getHttpStatus());
    }

    // @Valid 验证抛出的异常捕获
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ResponseValidatedFailedBody<Map<String, ArrayList<String>>>> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        Map<String, ArrayList<String>> errors = new HashMap<>();
        // 属性的多个验证不通过信息只显示一个
        // ex.getBindingResult().getFieldErrors().forEach(error -> {
        //     errors.put(error.getField(), error.getDefaultMessage());
        // });

        // 属性的所有验证不通过信息都显示
        ex.getBindingResult().getAllErrors().forEach(error -> {
            // System.out.println(((FieldError) error).getField());
            if(errors.get(((FieldError) error).getField()) == null){
                ArrayList<String> errorMsgs = new ArrayList<>();
                errorMsgs.add(error.getDefaultMessage());
                errors.put(((FieldError) error).getField(), errorMsgs);
            } else {
                ArrayList<String> errorMsgs = errors.get(((FieldError) error).getField());
                errorMsgs.add(error.getDefaultMessage());
                errors.put(((FieldError) error).getField(), errorMsgs);
            }
        });

        ResponseCode responseCode =ResponseCode.VALIDATED;
        ResponseValidatedFailedBody<Map<String, ArrayList<String>>> responseValidatedFailedBody = new ResponseValidatedFailedBody<>(responseCode.getCode(), responseCode.getMessage(), errors);
        return new ResponseEntity<>(responseValidatedFailedBody, responseCode.getHttpStatus());
    }

    // MissingServletRequestParameterException 捕获 @RequestParam 必填参数验证
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<ResponseValidatedFailedBody<Map<String, ArrayList<String>>>> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        Map<String, ArrayList<String>> errors = new HashMap<>();

        ArrayList<String> errorMsgs = new ArrayList<>();
        errorMsgs.add("The parameter '" + ex.getParameterName() + "' is required.");
        errors.put(ex.getParameterName(), errorMsgs);

        ResponseCode responseCode =ResponseCode.VALIDATED;
        ResponseValidatedFailedBody<Map<String, ArrayList<String>>> responseValidatedFailedBody = new ResponseValidatedFailedBody<>(responseCode.getCode(), responseCode.getMessage(), errors);
        return new ResponseEntity<>(responseValidatedFailedBody, responseCode.getHttpStatus());
    }

    // 登录验证异常
    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity<ResponseBody<String>> handleAuthenticationException(AuthenticationException e) {
        ResponseCode responseCode =ResponseCode.UNAUTHORIZED;
        ResponseBody<String> responseBody = new ResponseBody<>(responseCode.getCode(), e.getMessage());
        return new ResponseEntity<>(responseBody, responseCode.getHttpStatus());
    }

    // 权限验证异常
    @ExceptionHandler(PermissionException.class)
    public ResponseEntity<ResponseBody<String>> handlePermissionException(PermissionException e) {
        ResponseCode responseCode =ResponseCode.NO_PERMISSION;
        ResponseBody<String> responseBody = new ResponseBody<>(responseCode.getCode(), e.getMessage());
        return new ResponseEntity<>(responseBody, responseCode.getHttpStatus());
    }
}
